package com.iris.live.services.data.repositories.impl;

import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.iris.live.services.models.PageData;
import org.hibernate.SQLQuery;
import org.hibernate.jpa.HibernateQuery;
import org.hibernate.transform.Transformers;
import org.hibernate.type.Type;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.math.BigInteger;
import java.util.List;
import java.util.Map;

/**
 * Created by sxy on 2016/7/28.
 */
public abstract class BaseRepository {

    @PersistenceContext
    protected EntityManager entities;

    protected <T> T getScalar(String sql, Class<T> clazz) {
        return this.getScalar(sql, Maps.newHashMap(), clazz);
    }

    protected <T> T getScalar(String sql, Map params, Class<T> clazz) {
        List list = this.getList(sql, params);
        if (list.size() == 0) {
            return null;
        }

        Map first = (Map) Iterables.get(list, 0);
        if (first.entrySet().size() == 0) {
            return null;
        }

        Map.Entry entry = (Map.Entry) Iterables.get(first.entrySet(), 0);
        return (T) entry.getValue();
    }

    protected List getList(String sqlStr) {
        return this.getList(sqlStr, Maps.newHashMap());
    }

    protected List getList(String sqlStr, Map params) {
        Query query = this.entities.createNativeQuery(sqlStr);
        if (params != null) {
            for (Object key : params.keySet()) {
                query.setParameter((String) key, params.get(key));
            }
        }
        return this.toMap(query);
    }

    protected List getList(String sqlStr, Map params, Class clazz) {
        Query query = this.entities.createNativeQuery(sqlStr,clazz);
        if (params != null) {
            for (Object key : params.keySet()) {
                query.setParameter((String) key, params.get(key));
            }
        }
        return query.getResultList();
    }

    protected int executeUpdate(String sqlStr, Map params) {
        Query query = this.entities.createNativeQuery(sqlStr);
        if (params != null) {
            for (Object key : params.keySet()) {
                query.setParameter((String) key, params.get(key));
            }
        }
        return query.executeUpdate();
    }

    protected List getEntityList(String sqlStr, Map params) {
        Query query = this.entities.createQuery(sqlStr);
        if (params != null) {
            for (Object key : params.keySet()) {
                query.setParameter((String) key, params.get(key));
            }
        }

        return query.getResultList();
    }

    protected int getCount(String sqlStr) {
        return this.getCount(sqlStr, Maps.newHashMap());
    }

    protected int getCount(String sqlStr, Map params) {
        Query query = this.entities.createNativeQuery(sqlStr);
        if (params != null) {
            for (Object key : params.keySet()) {
                query.setParameter((String) key, params.get(key));
            }
        }

        BigInteger result = (BigInteger) query.getSingleResult();
        return result.intValueExact();
    }

    protected PageData getPage(String sqlStr, int pageSize, int pageIndex) {
        return this.getPage(sqlStr, Maps.newHashMap(), pageSize, pageIndex);
    }

    protected PageData getPage(String sqlStr, Map params, int pageSize, int pageIndex) {
        List data = null;
        int total = 0;

        String totalCount = "totalCount";
        if(params.containsKey(totalCount)){
            total = Integer.parseInt(params.get(totalCount).toString());
            params.remove(totalCount);
        }

        if (pageSize == 0 && pageIndex == 0){
            data = this.getList(sqlStr,params);
        }else{
            data = this.getList(String.format("%s limit %d, %d", sqlStr, pageIndex * pageSize, pageSize), params);
        }

        //优化分页查询
        if(total == 0){ //重新计算中总条数
            total = this.getCount(String.format("select cast(count(1) as UNSIGNED) rows from (%s) as q", sqlStr), params);
        }
        //int total = this.getCount(String.format("select cast(count(1) as UNSIGNED) rows from (%s) as q", sqlStr), params);

        return new PageData(data, total);
    }

    private List toMap(Query query) {
        if (query instanceof HibernateQuery) {
            query.unwrap(HibernateQuery.class)
                    .getHibernateQuery()
                    .setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
            return query.getResultList();
        }

        throw new IllegalStateException();
    }

    private void addScalar(Query query, String column, Type type) {
        if (query instanceof HibernateQuery) {
            query.unwrap(SQLQuery.class).addScalar(column, type);
        }

        throw new IllegalStateException();
    }
}
